/*
 * @Date: 2025-07-21 23:28:55
 * @LastEditors: 贾二小 erxiao.jia@outlook.com
 * @LastEditTime: 2025-07-21 23:29:01
 * @FilePath: /admin-vue/src/composables/useStorage.ts
 */
import localforage from 'localforage'

/** The storage type */
export type StorageType = 'local' | 'session'

export function createStorage<T extends object>(type: StorageType, storagePrefix: string) {
  const stg = type === 'session' ? window.sessionStorage : window.localStorage

  const storage = {
    /**
     * Set session
     *
     * @param key Session key
     * @param value Session value
     */
    set<K extends keyof T>(key: K, value: T[K]) {
      const json = JSON.stringify(value)

      stg.setItem(`${storagePrefix}${key as string}`, json)
    },
    /**
     * Get session
     *
     * @param key Session key
     */
    get<K extends keyof T>(key: K): T[K] | null {
      const json = stg.getItem(`${storagePrefix}${key as string}`)
      if (json) {
        let storageData: T[K] | null = null

        try {
          storageData = JSON.parse(json)
        } catch {}

        if (storageData) {
          return storageData as T[K]
        }
      }

      stg.removeItem(`${storagePrefix}${key as string}`)

      return null
    },
    remove(key: keyof T) {
      stg.removeItem(`${storagePrefix}${key as string}`)
    },
    clear() {
      stg.clear()
    },
  }
  return storage
}

type LocalForage<T extends object> = Omit<
  typeof localforage,
  'getItem' | 'setItem' | 'removeItem'
> & {
  getItem<K extends keyof T>(
    key: K,
    callback?: (err: any, value: T[K] | null) => void,
  ): Promise<T[K] | null>

  setItem<K extends keyof T>(
    key: K,
    value: T[K],
    callback?: (err: any, value: T[K]) => void,
  ): Promise<T[K]>

  removeItem(key: keyof T, callback?: (err: any) => void): Promise<void>
}

type LocalforageDriver = 'local' | 'indexedDB' | 'webSQL'

export function createLocalforage<T extends object>(driver: LocalforageDriver) {
  const driverMap: Record<LocalforageDriver, string> = {
    local: localforage.LOCALSTORAGE,
    indexedDB: localforage.INDEXEDDB,
    webSQL: localforage.WEBSQL,
  }

  localforage.config({
    driver: driverMap[driver],
  })

  return localforage as LocalForage<T>
}
